package com.gitee.luosl.cola.match.pattern;

import com.gitee.luosl.cola.lang.Tuple3;
import com.gitee.luosl.cola.lang.function.Predicate3;

import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

/**
 * Created by luosl on 2021/03/30/9:46
 */
abstract public class Pattern3<T, T1, T2, T3> implements Pattern<T, Tuple3<T1, T2, T3>>{


    public static <T, T1, T2, T3, R1, R2, R3> Pattern3<T, R1, R2, R3> of(
            Class<? super T> clazz,
            Predicate<T> predicate,
            Pattern<T1, R1> pattern1, Pattern<T2, R2> pattern2, Pattern<T3, R3> pattern3,
            Function<T, Tuple3<T1, T2, T3>> unapply) {
        return new Pattern3<T, R1, R2, R3>() {
            @Override
            public boolean isDefinedAt(T value) {
                Tuple3<T1, T2, T3> unapplyValue = unapply.apply(value);
                return clazz.isInstance(value)
                        && predicate.test(value)
                        && pattern1.isDefinedAt(unapplyValue._1)
                        && pattern2.isDefinedAt(unapplyValue._2)
                        && pattern3.isDefinedAt(unapplyValue._3);
            }

            @Override
            public Tuple3<R1, R2, R3> apply(T value) {
                return unapply.apply(value)
                        .map1(pattern1::apply)
                        .map2(pattern2::apply)
                        .map3(pattern3::apply);
            }
        };

    }

    public static <T, T1, T2, T3> Pattern3<T, T1, T2, T3> of(Pattern<T, Tuple3<T1, T2, T3>> pattern) {
        return new Pattern3<T, T1, T2, T3>() {
            @Override
            public boolean isDefinedAt(T value) {
                return pattern.isDefinedAt(value);
            }

            @Override
            public Tuple3<T1, T2, T3> apply(T value) {
                return pattern.apply(value);
            }
        };
    }

}
